<template>
  <div class="publish">
    <div class="publish__container">
      <!-- 主编辑区域 -->
      <Editor
        ref="editorRef"
        v-model:title="articleForm.title"
        v-model:content="articleForm.content"
        v-model:showConfig="showConfig"
        v-model:showMediaLibrary="showMediaLibrary"
        :showCatalog="showCatalog"
        :isSaving="isSaving"
        :saveStatusText="saveStatusText"
        :saveStatusType="saveStatusType"
        :editorTheme="editorTheme"
        :editorConfig="editorConfig"
        :articleForm="articleForm"
        @save-draft="saveDraft"
        @save-content="saveContent"
        @publish="publishArticle"
        @toggle-catalog="toggleCatalog"
        @editor-change="handleEditorChange"
        @html-changed="handleHtmlChanged"
        @get-catalog="handleGetCatalog"
        @open-media-library="handleOpenMediaLibrary"
      />

      <!-- 右侧配置面板 -->
      <ConfigPanel
        v-model="showConfig"
        :articleForm="articleForm"
        @update:articleForm="(val) => Object.assign(articleForm, val)"
        ref="configPanelRef"
      />

      <!-- 素材库 -->
      <MediaLibrary
        v-if="showMediaLibrary"
        v-model="showMediaLibrary"
        @select-media="handleMediaSelect"
        @batch-insert="handleMediaBatchInsert"
      />
    </div>
  </div>
</template>

<script setup>
/**
 * 发布文章组件
 *
 * 功能：
 * 1. 文章编辑器与预览
 * 2. 文章配置管理（分类、类型、状态等）
 * 3. 素材库管理（插入图片、文档等）
 * 4. 草稿自动保存
 * 5. 支持发布与保存草稿
 */
import { ref, reactive, computed, watch, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import Editor from './components/Editor.vue'
import ConfigPanel from './components/ConfigPanel.vue'
import MediaLibrary from './components/MediaLibrary.vue'
import 'md-editor-v3/lib/style.css'
import dayjs from 'dayjs'
import { articleApi } from '@/api/article'

const route = useRoute()
const router = useRouter()

// =============== 状态与配置 ===============

/**
 * 加载状态标志
 * 用于处理数据加载过程中的UI显示和防止意外操作
 */
const isLoading = ref(false)

/**
 * 编辑器引用
 * 用于获取编辑器实例和调用编辑器方法
 * @type {import('vue').Ref<any>}
 */
const editorRef = ref(null)

/**
 * 配置面板引用
 * 用于调用配置面板方法
 */
const configPanelRef = ref(null)

/**
 * 编辑器配置对象
 * 控制编辑器的行为和外观
 */
const editorConfig = {
  mode: 'editable', // 编辑模式
  preview: true, // 开启预览
  previewTheme: 'default', // 预览主题
}

/**
 * 编辑器主题
 * 支持 'light' 或 'dark'
 */
const editorTheme = 'light'

/**
 * 文章表单数据
 * 包含文章的所有可配置属性
 */
const articleForm = reactive({
  id: '', // 文章ID
  title: '', // 文章标题
  content: '', // 文章内容
  categoryId: '1', // 文章分类ID
  type: '1', // 文章类型：1=公开，2=私密，3=加密
  status: '0', // 文章状态：0=草稿，1=已发布
  orderNum: 5, // 排序号
  description: '', // 文章摘要
  picUrl: '', // 封面图片URL
  password: '', // 加密密码（类型为3时使用）
  tags: [], // 文章标签名称集合
  coverStyle: '', // 封面样式
})

/**
 * 保存相关状态
 */
const isSaving = ref(false) // 是否正在保存
const lastSaveTime = ref(null) // 最后保存时间
const hasEdited = ref(false) // 是否已编辑（任何变更）
const hasRealEdit = ref(false) // 是否实际变更内容（防止加载时触发保存）
let saveTimeout = null // 自动保存定时器

/**
 * 面板控制状态
 */
const showConfig = ref(false) // 显示配置面板
const showCatalog = ref(false) // 显示目录
const showMediaLibrary = ref(false) // 显示素材库

/**
 * 保存状态文本
 * 根据保存状态动态显示不同的提示文本
 */
const saveStatusText = computed(() => {
  if (isSaving.value) return '正在保存...'
  if (lastSaveTime.value) return `最后保存于 ${lastSaveTime.value}`
  return '尚未保存'
})

// 新增：保存状态类型（圆点颜色）
const saveStatusType = computed(() => {
  // 未保存（有变更）为 danger，已保存为 success
  return hasEdited.value ? 'danger' : 'success'
})

/**
 * 当前文章ID
 * 统一处理路由中的 id 和 editId 参数
 */
const currentArticleId = computed(() => {
  return route.query.id || route.query.editId
})

// =============== 方法 ===============

/**
 * 获取文章详情
 * 根据ID加载文章数据
 * @param {string|number} id - 文章ID
 */
const fetchArticleDetail = async (id) => {
  try {
    isLoading.value = true // 开始加载
    const res = await articleApi.getDetail(id)
    if (res) {
      // 回显数据
      articleForm.id = res.id || id
      articleForm.title = res.title
      articleForm.content = res.content
      articleForm.categoryId = res.category?.id || res.categoryId
      articleForm.type = res.type
      articleForm.status = res.status
      articleForm.orderNum = res.orderNum || 0
      articleForm.description = res.description
      articleForm.picUrl = res.picUrl
      articleForm.password = res.password
      articleForm.coverStyle = res.coverStyle

      // 处理标签数据回显 - 用于 el-select 绑定 name
      articleForm.tags = Array.isArray(res.tags) ? res.tags.map((t) => t.name) : []

      // 重置保存状态
      hasEdited.value = false
      hasRealEdit.value = false
      lastSaveTime.value = dayjs().format('HH:mm:ss')
    }
  } catch (error) {
    console.error('获取文章详情失败:', error)
    ElMessage.error('获取文章详情失败')
  } finally {
    // 使用 setTimeout 确保数据加载完成后再允许监听变化
    setTimeout(() => {
      isLoading.value = false // 加载完成
    }, 500)
  }
}

/**
 * 保存草稿
 * 根据是否有ID决定创建新文章或更新现有文章
 */
const saveDraft = async () => {
  // 标题和内容必填
  if (!articleForm.title || !articleForm.content) {
    return
  }

  try {
    isSaving.value = true
    const articleId = currentArticleId.value

    if (articleId) {
      // 编辑模式
      const requestData = {
        ...articleForm,
        id: articleId,
        status: '0', // 设置为已发布状态
      }
      const res = await articleApi.edit(requestData)
      if (res) {
        lastSaveTime.value = dayjs().format('HH:mm:ss')
        hasEdited.value = false
        hasRealEdit.value = false
      }
    } else {
      // 新增模式
      const res = await articleApi.saveDraft(articleForm)
      if (res) {
        // 更新文章ID
        articleForm.id = res
        // 将返回的 id 添加到路由参数
        router.replace({
          query: { ...route.query, id: res, status: '0' },
        })
        lastSaveTime.value = dayjs().format('HH:mm:ss')
        hasEdited.value = false
        hasRealEdit.value = false
      }
    }
  } catch (error) {
    console.error('保存草稿失败:', error)
    ElMessage.error('保存草稿失败')
  } finally {
    isSaving.value = false
  }
}

/**
 * 发布文章
 * 将文章状态设置为已发布并保存
 */
const publishArticle = async () => {
  try {
    // 校验标题和内容
    if (!articleForm.title || !articleForm.title.trim()) {
      ElMessage.warning('请输入文章标题')
      return
    }
    if (!articleForm.content || !articleForm.content.trim()) {
      ElMessage.warning('请输入文章内容')
      return
    }

    const articleId = currentArticleId.value
    if (articleId) {
      // 编辑模式
      const requestData = {
        ...articleForm,
        id: articleId,
        status: '1', // 设置为已发布状态
      }
      const res = await articleApi.edit(requestData)
      if (res) {
        ElMessage.success('更新成功')
        router.push('/article/list')
      }
    } else {
      // 新增模式
      const res = await articleApi.publish({
        ...articleForm,
        status: '1', // 设置为已发布状态
      })
      if (res) {
        ElMessage.success('发布成功')
        router.push('/article/list')
      }
    }
  } catch (error) {
    console.error('发布失败:', error)
    ElMessage.error('发布失败')
  }
}

/**
 * 自动保存处理
 * 在内容变更后延迟保存
 */
const handleAutoSave = () => {
  // 如果正在加载数据，不触发自动保存
  if (isLoading.value) return

  // 如果没有任何内容，不触发保存
  if (!articleForm.title && !articleForm.content) return

  // 标记为已编辑
  hasEdited.value = true

  if (saveTimeout) clearTimeout(saveTimeout)

  // 如果已经有 id，直接使用现有 id
  const articleId = currentArticleId.value

  saveTimeout = setTimeout(() => {
    // 再次检查是否正在加载
    if (isLoading.value) return

    if (articleId) {
      // 如果已经有 id，只在有实际改动时才保存
      if (hasEdited.value && hasRealEdit.value) {
        saveDraft()
      }
    } else {
      // 第一次保存时创建新数据，但也要确保有实际编辑
      if (hasRealEdit.value) {
        saveDraft()
      }
    }
  }, 2000)
}

/**
 * 切换目录显示
 */
const toggleCatalog = () => {
  showCatalog.value = !showCatalog.value
  editorRef.value?.toggleCatalog(showCatalog.value)
}

/**
 * 处理打开素材库
 * 在显示素材库前检查编辑器实例是否就绪
 */
const handleOpenMediaLibrary = () => {
  // 在显示素材库之前，先确保编辑器实例存在
  if (!editorRef.value?.editorRef) {
    ElMessage.warning('编辑器未就绪，请稍后再试')
    return
  }
  showMediaLibrary.value = true
}

/**
 * 编辑器内容变化处理
 * @param {string} content - 变更后的内容
 */
const handleEditorChange = (content) => {
  // 如果正在加载数据，不触发自动保存
  if (isLoading.value) return

  // 只有当内容实际变化时才标记为已编辑
  if (content !== articleForm.content) {
    hasRealEdit.value = true
    handleAutoSave()
  }
}

/**
 * HTML内容变化处理
 * @param {string} html - 变更后的HTML内容
 */
const handleHtmlChanged = (html) => {
  // 可以在这里处理HTML内容变化，如提取摘要
}

/**
 * 目录变化处理
 * @param {Array} catalog - 目录数据
 */
const handleGetCatalog = (catalog) => {
  // 可以在这里处理目录数据，如更新目录状态
}

/**
 * 处理媒体选择
 * @param {Object} item - 选中的媒体项
 */
const handleMediaSelect = (item) => {
  // 根据文件类型生成不同的 markdown 语法
  const markdown =
    item.type === 'image'
      ? `![${item.name}](${item.url})` // 图片语法
      : `[${item.name}](${item.url})` // 链接语法

  // 获取编辑器实例并插入内容
  const editor = editorRef.value?.editorRef
  if (!editor) {
    ElMessage.error('编辑器实例未就绪，请重试')
    return
  }

  // 插入内容到编辑器
  editor.insert((selectedText) => ({
    // 如果有选中文本，在选中文本后插入；否则直接插入
    targetValue: selectedText ? `${selectedText}\n${markdown}` : markdown,
    select: true,
    deviationStart: 0,
    deviationEnd: 0,
  }))
}

/**
 * 处理批量插入
 * @param {Array} items - 选中的媒体项数组
 */
const handleMediaBatchInsert = (items) => {
  // 生成所有选中项的 Markdown 内容，以空行分隔
  const markdown = items
    .map((item) =>
      item.type === 'image' ? `![${item.name}](${item.url})` : `[${item.name}](${item.url})`,
    )
    .join('\n\n')

  // 获取编辑器实例并插入内容
  const editor = editorRef.value?.editorRef
  if (!editor) {
    ElMessage.error('编辑器实例未就绪，请重试')
    return
  }

  // 插入内容到编辑器
  editor.insert((selectedText) => ({
    // 如果有选中文本，在选中文本后插入；否则直接插入
    targetValue: selectedText ? `${selectedText}\n${markdown}` : markdown,
    select: true,
    deviationStart: 0,
    deviationEnd: 0,
  }))
}

/**
 * 编辑器 onSave 事件：仅保存内容，不跳转
 */
const saveContent = async () => {
  // 标题和内容必填
  if (!articleForm.title || !articleForm.content) {
    return
  }
  try {
    isSaving.value = true
    const articleId = currentArticleId.value
    if (articleId) {
      // 编辑模式
      const requestData = {
        ...articleForm,
        id: articleId,
      }
      const res = await articleApi.edit(requestData)
      if (res) {
        lastSaveTime.value = dayjs().format('HH:mm:ss')
        hasEdited.value = false
        hasRealEdit.value = false
      }
    } else {
      // 新增模式
      const res = await articleApi.saveDraft(articleForm)
      if (res) {
        // 更新文章ID
        articleForm.id = res
        router.replace({
          query: { ...route.query, id: res },
        })
        lastSaveTime.value = dayjs().format('HH:mm:ss')
        hasEdited.value = false
        hasRealEdit.value = false
      }
    }
  } catch (error) {
    console.error('保存内容失败:', error)
    ElMessage.error('保存内容失败')
  } finally {
    isSaving.value = false
  }
}

// =============== 监听器 ===============

/**
 * 监听路由参数变化
 * 当ID变化时重新加载文章数据
 */
watch(
  () => currentArticleId.value,
  (newId) => {
    if (newId) {
      fetchArticleDetail(newId)
      // 重置编辑状态，避免加载后立即触发保存
      hasRealEdit.value = false
    } else {
      // 如果没有 id，说明是新增，重置表单
      articleForm.id = ''
      articleForm.title = ''
      articleForm.content = ''
      articleForm.categoryId = '1'
      articleForm.type = '1'
      articleForm.status = '0'
      articleForm.orderNum = 5
      articleForm.description = ''
      articleForm.picUrl = ''
      articleForm.password = ''
      articleForm.tags = []
      articleForm.coverStyle = ''
      hasEdited.value = false
      hasRealEdit.value = false
      lastSaveTime.value = null
    }
  },
  { immediate: true },
)

/**
 * 监听标题和内容变化
 * 触发自动保存逻辑
 */
watch(
  [() => articleForm.title, () => articleForm.content],
  (newValues, oldValues) => {
    // 如果正在加载数据，不触发自动保存
    if (isLoading.value) return

    // 只有当值实际发生变化时才触发自动保存
    if (
      (oldValues[0] !== undefined && newValues[0] !== oldValues[0]) ||
      (oldValues[1] !== undefined && newValues[1] !== oldValues[1])
    ) {
      if (!articleForm.title && !articleForm.content) return
      hasRealEdit.value = true // 标记为实际编辑
      handleAutoSave()
    }
  },
  { deep: true },
)
</script>

<style lang="scss" scoped>
// 导入主题变量和混合器
@use '@/assets/styles/theme/base.scss' as *;
@use '@/assets/styles/mixins.scss' as *;

/**
 * 发布页面样式
 * 使用BEM命名规范
 */
.publish {
  height: 100%;
  background-color: $bg-base;
  overflow: hidden;

  /**
   * 主容器
   * 用于布局编辑器和侧边面板
   */
  &__container {
    height: 100%;
    position: relative;
  }
}
</style>
